﻿using System.Collections.Generic;
using Manoli.Utils.CSharpFormat;

// expanded from original code found here: http://forums.asp.net/p/1087581/1635776.aspx
// advanced formatters can be found here: http://manoli.net/csharpformat/

namespace Cyotek.Web.BbCodeFormatter
{
    /// <summary>
    /// BBCode Helper allows formatting of text
    /// without the need to use html
    /// </summary>
    public class BbCodeClearer
    {
        #region  Private Class Member Declarations

        static List<IHtmlFormatter> _formatters;

        #endregion  Private Class Member Declarations

        #region  Static Constructors

        static BbCodeClearer()
        {
            string orderedListFormat;

            _formatters = new List<IHtmlFormatter>();

            _formatters.Add(new RegexFormatter(@"<(.|\n)*?>", string.Empty));

            // using the below three formatters make a complete mess of preformatted text. 
            // I've disabled them and replaced them with a slower version that will replace line breaks only when they are not within one of the specified blocks.

            //_formatters.Add(new SearchReplaceFormatter("\r", ""));
            //_formatters.Add(new SearchReplaceFormatter("\n\n", "</p><p>"));
            //_formatters.Add(new SearchReplaceFormatter("\n", "<br />"));
            _formatters.Add(new LineBreaksFormatter(new string[] { "html", "csharp", "code", "jscript", "sql", "vb", "php" }));

            _formatters.Add(new SearchReplaceFormatter("</p><p>", "\n"));
            _formatters.Add(new SearchReplaceFormatter("</div><div>", "\n"));
            _formatters.Add(new SearchReplaceFormatter("</div>", "\n"));
            _formatters.Add(new SearchReplaceFormatter("</p>", "\n"));
            _formatters.Add(new SearchReplaceFormatter("<p>", ""));
            _formatters.Add(new SearchReplaceFormatter("<div>", ""));

            _formatters.Add(new RegexFormatter(@"\[b(?:\s*)\]((.|\n)*?)\[/b(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[b(?:\s*)\]((.|\n)*?)\[/b(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[i(?:\s*)\]((.|\n)*?)\[/i(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[s(?:\s*)\]((.|\n)*?)\[/s(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[u(?:\s*)\]((.|\n)*?)\[/u(?:\s*)\]", "$1"));

            _formatters.Add(new RegexFormatter(@"\[left(?:\s*)\]((.|\n)*?)\[/left(?:\s*)]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[center(?:\s*)\]((.|\n)*?)\[/center(?:\s*)]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[right(?:\s*)\]((.|\n)*?)\[/right(?:\s*)]", "$1"));

            _formatters.Add(new RegexFormatter(@"\[code(?:\s*)\]((.|\n)*?)\[/code(?:\s*)]", "<div class=\"bbc-codetitle\">\n$1\n"));

            _formatters.Add(new RegexFormatter(@"\[quote=((.|\n)*?)(?:\s*)\]", "\""));
            _formatters.Add(new RegexFormatter(@"\[quote(?:\s*)\]", "\""));
            _formatters.Add(new RegexFormatter(@"\[/quote(?:\s*)\]", "\""));

            _formatters.Add(new RegexFormatter(@"\[url(?:\s*)\]www\.(.*?)\[/url(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[url(?:\s*)\]((.|\n)*?)\[/url(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[url=""((.|\n)*?)(?:\s*)""\]((.|\n)*?)\[/url(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[url=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/url(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[link(?:\s*)\]((.|\n)*?)\[/link(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[link=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/link(?:\s*)\]", "$"));

            _formatters.Add(new RegexFormatter(@"\[img(?:\s*)\]((.|\n)*?)\[/img(?:\s*)\]", ""));
            _formatters.Add(new RegexFormatter(@"\[img align=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/img(?:\s*)\]", ""));
            _formatters.Add(new RegexFormatter(@"\[img=((.|\n)*?)x((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/img(?:\s*)\]", ""));

            _formatters.Add(new RegexFormatter(@"\[color=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/color(?:\s*)\]", "$3"));

            _formatters.Add(new RegexFormatter(@"\[highlight(?:\s*)\]((.|\n)*?)\[/highlight(?:\s*)]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[spoiler(?:\s*)\]((.|\n)*?)\[/spoiler(?:\s*)]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[indent(?:\s*)\]((.|\n)*?)\[/indent(?:\s*)]", "$1"));

            _formatters.Add(new RegexFormatter(@"\[hr(?:\s*)\]", "\n"));
            _formatters.Add(new RegexFormatter(@"\[rule=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/rule(?:\s*)\]", ""));

            _formatters.Add(new RegexFormatter(@"\[email(?:\s*)\]((.|\n)*?)\[/email(?:\s*)\]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[email=""((.|\n)*?)(?:\s*)""\]((.|\n)*?)\[/email(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[email=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/email(?:\s*)\]", "$3"));

            _formatters.Add(new RegexFormatter(@"\[small(?:\s*)\]((.|\n)*?)\[/small(?:\s*)]", "$1"));
            _formatters.Add(new RegexFormatter(@"\[size=+((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/size(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[size=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/size(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[font=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/font(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[align=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/align(?:\s*)\]", "$3"));
            _formatters.Add(new RegexFormatter(@"\[float=((.|\n)*?)(?:\s*)\]((.|\n)*?)\[/float(?:\s*)\]", "$3"));

            orderedListFormat = "- $1";
            _formatters.Add(new RegexFormatter(@"\[\*(?:\s*)]\s*([^\[]*)", "$1"));
            _formatters.Add(new RegexFormatter(@"\[list(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", "- $1\n"));
            _formatters.Add(new RegexFormatter(@"\[list=1(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", orderedListFormat, false));
            _formatters.Add(new RegexFormatter(@"\[list=i(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", orderedListFormat, false));
            _formatters.Add(new RegexFormatter(@"\[list=I(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", orderedListFormat, false));
            _formatters.Add(new RegexFormatter(@"\[list=a(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", orderedListFormat, false));
            _formatters.Add(new RegexFormatter(@"\[list=A(?:\s*)\]((.|\n)*?)\[/list(?:\s*)\]", orderedListFormat, false));
        }

        #endregion  Static Constructors

        #region  Public Class Methods

        public static string Format(string data)
        {
            foreach (IHtmlFormatter formatter in _formatters)
                data = formatter.Format(data);

            return StripTagsCharArray(data);
        }

        public static string StripTagsCharArray(string source)
        {
            char[] array = new char[source.Length];
            int arrayIndex = 0;
            bool inside = false;

            for (int i = 0; i < source.Length; i++)
            {
                char let = source[i];
                if (let == '<')
                {
                    inside = true;
                    continue;
                }
                if (let == '>')
                {
                    inside = false;
                    continue;
                }
                if (!inside)
                {
                    array[arrayIndex] = let;
                    arrayIndex++;
                }
            }
            return new string(array, 0, arrayIndex);
        }


        #endregion  Public Class Methods
    }
}
